package com.generate.table;


import com.excel.read.ExcelUtils;
import com.generate.annotation.TableColumnName;
import com.generate.span.DefaultTheadBodyCCCallBack;
import com.generate.span.TableCallBack;
import com.generate.span.TheadBodyTable;

import java.lang.reflect.Field;
import java.util.*;

public class TableHelper {

    public static final Table emptyTable = new Table();

    private static <T> Map<String, String> classToMap(T cls) {
        Map<String, String> map = new LinkedHashMap<>();
        if (cls == null) {
            return map;
        }
        Class<?> aClass = cls.getClass();
        try {
            while (!aClass.isAssignableFrom(Object.class)) {
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    declaredField.setAccessible(true);
                    Object obj = declaredField.get(cls);
                    declaredField.setAccessible(false);
                    map.put(declaredField.getName(), obj == null || String.valueOf(obj).equalsIgnoreCase("null") ? "" : String.valueOf(obj));
                }
                aClass = aClass.getSuperclass();
            }
            return map;
        } catch (Exception e) {

        }
        return map;
    }

    public static <T> List<Map<String, String>> classToListMap(List<T> classzs) {
        List<Map<String, String>> linkedList = new LinkedList<>();
        if (classzs == null) {
            return linkedList;
        }
        for (T t : classzs) {
            Map<String, String> map = classToMap(t);
            linkedList.add(map);
        }
        return linkedList;
    }

    public static <T> Table create(List<T> list, Class<T> tClass) {
        Table table = new Table();
        table.setTableData(classToListMap(list));
        table.setCells(classToTableCells(tClass));
        table.build();
        return table;
    }


    public static List<Table.Cell> classToTableCells(Class cls) {
        List<Table.Cell> cells = new LinkedList<>();
        Class<?> aClass = cls;
        try {
            while (!aClass.isAssignableFrom(Object.class)) {
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    TableColumnName annotation = declaredField.getAnnotation(TableColumnName.class);
                    String value;
                    if (annotation != null) {
                        value = annotation.value();

                    } else {
                        value = declaredField.getName();
                    }
                    Table.Cell cell = new Table.Cell();
                    cell.setField(value);
                    cell.setProp(declaredField.getName());
                    cells.add(cell);

                }
                aClass = aClass.getSuperclass();
            }
        } catch (Exception e) {

        }
        return cells;
    }

    public static <T> Table create(ExcelUtils<T> excelUtils) {
        Table table = new Table();
        if (excelUtils == null) {
            return table;
        }
        List<Map<String, String>> list = excelUtils.getList();
        List<Table.Cell> cells = new LinkedList<>();
        Map<String, String> headers = excelUtils.getHeaders();
        Tr tr = new Tr();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            Table.Cell cell = new Table.Cell();
            cell.setField(entry.getValue());
            cell.setProp(entry.getKey());
            cells.add(cell);
            Td td = new Td();
            td.setTitle(entry.getValue());
            tr.addTd(td);
        }
        table.addTr(tr);
        table.setCells(cells);
        table.setTableData(list);
        for (Map<String, String> stringStringMap : list) {
            tr = new Tr();
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                Td td = new Td();
                td.setTitle(stringStringMap.get(entry.getKey()));
                tr.addTd(td);
            }
            table.addTr(tr);
        }


        return table;
    }

    public  static <T extends Table> T  create(TableCallBack<T> tableCallBack) {
        T t = tableCallBack.create();
        tableCallBack.init(t);
        tableCallBack.build(t);
        return t;
    }


    public static <T> TheadBodyTable createTheadBodyTable(List<T> list, Class<T> tClass) {
        DefaultTheadBodyCCCallBack spanCallBack = new DefaultTheadBodyCCCallBack();
        TheadBodyTable table = spanCallBack.create();
        table.setTableData(classToListMap(list));
        table.setCells(classToTableCells(tClass));
        table.build(spanCallBack);
        return table;
    }

    public static Table create(TableCallBack... spanCallBacks) {
        Table table = new Table();
        Arrays.stream(spanCallBacks).sorted().forEach(table::build);
        return table;
    }
}
